Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[feature-hal-itm] Instrumented Trace Macrocell HAL API for SWO debug output #5956

Merged
merged 3 commits into from Feb 16, 2018
Merged

[feature-hal-itm] Instrumented Trace Macrocell HAL API for SWO debug output #5956

merged 3 commits into from Feb 16, 2018

Conversation

marcuschangarm
Copy link
Contributor

HAL API for initializing ITM and setting up SWO output.

Uses FileHandle redirection for debug output.

Note: this should be merged to a new feature branch and not to master.

Depends on: #5571

@marcuschangarm
Copy link
Contributor Author

@yogpan01 @TeroJaasko

This is what you really need for the miniclient.

@marcuschangarm
Copy link
Contributor Author

@0xc0170 @bulislaw

As we discussed. Can you create a feature branch please?

@mbed-ci
Copy link

mbed-ci commented Jan 29, 2018

@marcuschangarm, thank you for your changes. You should get some feedback from the following people shortly: @bulislaw @ARMmbed/team-nordic @geky @pan- @c1728p9 @SenRamakri @mbed-os-maintainers @scartmell-arm please review.

Copy link
Contributor

@kjbracey kjbracey left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, this is how the FileHandle stuff should work.

You could also make your target implement mbed_target_override_console so that stdout/stderr goes to SWO by default. Or the application itself can do mbed_overide_console.

If you do do that in the target, you may or may not want to take care in the hal ITM implementation so that it isn't the end of the world if stdout is a SingleWireOutput in the target code, and the application also defines their SingleWireOutput, so it is double inited. The serial API stuff has similar mucking around. (TBH I think that's something that shouldn't be encouraged, so feel free to not worry about that). It may be there's nothing really to do as your current HAL is singleton anyway, so SingleWireOutput has no state.

I'm kicking people for review on #5571.


#include "hal/itm_api.h"

class SingleWireOutput : public FileHandle {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To fit the pattern of the rest of the system, this would be drivers/SingleWireOutput.h - you've put the ITM bits in the HAL, and this is the corresponding C++ wrapper. So it goes with SPI and friends.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was hoping to eventually put it into mbed_retarget.cpp like you did with the serial class: https://github.com/kjbracey-arm/mbed-os/blob/d7e42d1f69e5a8f06441742d910d795c8ae22c85/platform/mbed_retarget.cpp#L128-L180

so that we can enable SWO from the config system.

My intention with this PR is to start some discussion about what would be right approach. @0xc0170 @bulislaw any comments?

Copy link
Contributor

@kjbracey kjbracey Jan 30, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm slightly wary of setting up a sort of "central registry" pattern where every potential device has to be plopped in there.

In #5558 there's a similar concept - the JSON choice of "default onboard network stack". You set nsapi.default-stack to either "LWIP" or "NANOSTACK". There's no central logic for that, but each of the two stacks has a code snippet that looks like

#define NANOSTACK 0x82917429
#if MBED_CONF_NSAPI_DEFAULT_STACK == NANOSTACK
OnboardNetworkStack &OnboardNetworkStack::get_default_instance() {
    return Nanostack::get_instance();
}
#endif

So only one of them will define that function.

Maybe the same concept would work here. JSON option in central place, but any target or library one can add a new selectable default without touching the core code - just invent a name.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Anyway, regardless of the "default console" selection, this needs to be exposed as a separate standalone device manually accessible as SingleWireOutput.

See my 18 Dec comments on #5356, where they're concentrating on alternative console, but I'm urging them to make sure that the device is always manually useable by the app without being forced to make it stdin/stdout.

The built-in FileHandles in my mbed_retarget.cpp are purely to preserve legacy behaviour. If anything, they will be moved out (@geky has suggested making Sink public, and discussions with @sg- have led to concensus that RawSerial should be a FileHandle, thus it can do the job of DirectSerial).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No problem, I'll move/rename it to mbed-os/drivers.

I'm fine with either invocation as well, but I think we should have it documented exactly how we expect people to do it!


virtual ssize_t read(void *buffer, size_t size) {
unsigned char *buf = static_cast<unsigned char *>(buffer);
buf[0] = 0;
Copy link
Contributor

@kjbracey kjbracey Jan 29, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's better to just return 0 (indicating "end of file") or an error code (not sure which - -EBADF = "not valid file descriptor open for reading"?; -ENXIO = "... request was outside the capabilities of the device"?). Don't know whether EOF or error is better.

My dummy device implementation inside the retarget code is only reading endless NUL bytes to preserve the legacy behaviour of stdin with DEVICE_SERIAL unset. I don't think that's actually useful, or what you should do for something new.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did a bit of background reading to compare other systems. This is an interesting general question.

/dev/null returns EOF if opened for input. But that's more likely to be used manually as a redirect for processes that expect a redirect from file, and hence understand/expect EOF on stdin.

Many real devices probably would do ENXIO on the attempt to open for read. I guess that means attempts to use a read-only device as process input would fail the read open and then you'd get EBADF later.

Linux gives EBADF if you read from a file that's open for output only.

When you nohup and detach a process in Linux it does seem you get EBADF on input (and you can change that to EOF if you redirect from /dev/null). POSIX says behaviour of nohup input is up to the implementation - it might leave input from original terminal, or get it from a file.

On balance, I guess I'll say EBADF is what to do on read. This is a "standalone" FileHandle where it's automatically opened on construction, so we should assume that the implicit open is write-only, thus give EBADF on read attempts.

If there was a device filing system, so we were able to participate in the open call, we'd return ENXIO on the attempt to open for read.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you! I'll change it to EBADF.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lesson learned, looks like I have some filesystems to update...

Copy link
Contributor

@kjbracey kjbracey Jan 30, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, normal filesystems might be a bit different. Eg EACCES for access violation rather than ENXIO. I was only really thinking about devices, and particularly considering this odd case of "opened by construction" objects.

I just spend too much time Googling "POSIX open" or "POSIX read" to check POSIX specs for my own good...

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, in the open group docs for write:
http://pubs.opengroup.org/onlinepubs/9699919799/functions/write.html

[EBADF]
The fildes argument is not a valid file descriptor open for writing.

Pretty straightforward for POSIX docs actually. 😆

A quick test program confirms this is what Linux returns.

Fortunately reading/writing to a file after opening it in a specific mode is pretty uncommon outside of user errors. I'd be worried if someone was relying on a specific error code in that situation.

virtual ssize_t write(const void *buffer, size_t size) {
const unsigned char *buf = static_cast<const unsigned char *>(buffer);
for (size_t i = 0; i < size; i++) {
ITM_SendChar(buf[i]);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This isn't in itm_api.h? Skipping a layer?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ITM_SendChar is defined in:

cmsis/TARGET_CORTEX_M/core_cm3.h
cmsis/TARGET_CORTEX_M/core_cm4.h
etc.

I'm not sure how to explicitly include the right header file based on core.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ah, #include "cmsis.h" should do the trick.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, cmsis should be used as a generic cmsis header file

@TeroJaasko
Copy link
Contributor

Works on my NRF52_DK. Redirecting the console is now really easy:

FileHandle *mbed::mbed_override_console(int fd) {
    static SingleWireOutput swo_serial;
    return &swo_serial;
}

int main() {
    while (true) {
        wait(0.5);
        printf("hello world\n");
    }
}


#if defined(DEVICE_ITM)

#include "hal/itm_api.h"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you'll need to include platform/FileHandle.h.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you! I'll add the missing include.

@yogpan01
Copy link
Contributor

@marcuschangarm Thanks for this ! @0xc0170 When can this be merged into MASTER. We are currently blocked on using nRF52 for our development because of this. We need this ASAP !
@JanneKiiskila @sg- FYI

@0xc0170
Copy link
Contributor

0xc0170 commented Jan 30, 2018

@0xc0170 When can this be merged into MASTER

First, Filehandle PR needs to be integrated first (there are still some reviews + tests outstanding). As soon as that one is in, this should be updated to reflect the latest changes.

@marcuschangarm
Copy link
Contributor Author

Rebased with master to get #5571

@marcuschangarm
Copy link
Contributor Author

@0xc0170 @yogpan01

@0xc0170 When can this be merged into MASTER

First, Filehandle PR needs to be integrated first (there are still some reviews + tests outstanding). As soon as that one is in, this should be updated to reflect the latest changes.

FileHandle PR has been merged and this PR has been rebased. Now what? 😄

@kjbracey
Copy link
Contributor

kjbracey commented Feb 9, 2018

/morph build

@kjbracey
Copy link
Contributor

kjbracey commented Feb 9, 2018

@SenRamakri, @c1728p9, @bulislaw - dependency is now merged, so this could proceed. Please review.

I'm happy with the FileHandle end of this. Are people happy with the HAL API?

@mbed-ci
Copy link

mbed-ci commented Feb 9, 2018

Build : SUCCESS

Build number : 1101
Build artifacts/logs : http://mbed-os.s3-website-eu-west-1.amazonaws.com/?prefix=builds/5956/

Triggering tests

/morph test
/morph uvisor-test
/morph export-build

@mbed-ci
Copy link

mbed-ci commented Feb 9, 2018

@mbed-ci
Copy link

mbed-ci commented Feb 9, 2018

Copy link
Member

@bulislaw bulislaw left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good, except doxygen in the headers is missing. Also can you add porting guide for itm and probably some handbook page for how to actually use it.

hal/itm_api.h Outdated
extern "C" {
#endif

void itm_init(void);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know it's a dummy function but could we get some description? What should it initialise (channel 0?). Here's some example https://github.com/ARMmbed/mbed-os/blob/feature-hal-spec-rtc/hal/rtc_api.h also can you add it to doxy please.
@c1728p9 any comments?

#include "hal/itm_api.h"
#include "platform/FileHandle.h"

class SerialWireOutput : public FileHandle {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not a single comment :P @SenRamakri please review

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seemed a bit premature until we've all agreed on the functionality! 😄

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@marcuschangarm - Since this is coming into master its better to have some comments/documentation on what this class is?

#include "hal/itm_api.h"
#include "platform/FileHandle.h"

class SerialWireOutput : public FileHandle {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@marcuschangarm - Since this is coming into master its better to have some comments/documentation on what this class is?

CMU->OSCENCMD = CMU_OSCENCMD_AUXHFRCOEN;

// Wait until clock is ready
while (!(CMU->STATUS & CMU_STATUS_AUXHFRCORDY));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Potentially infinite loop, can we please break this loop and return with an error after waiting enough? I don't how much is "enough", you can define that.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All Silicon Labs clock initialization code use this kind of infinite loop. Changing this single loop with an arbitrary loop counter would break the pattern.

uint32_t div = freq / 875000;
TPI->ACPR = div - 1;

ITM->LAR = 0xC5ACCE55;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be better if we can #define these magic values.

ITM->TCR = 0x0;
TPI->SPPR = 2;
ITM->TPR = 0x0;
DWT->CTRL = 0x400003FF;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Magic value 0x400003FF and others below. Can we please define them with corresponding fields? Also it looks like, we are writing to upper nibble which is read-only I guess. We are also enabling CYCCNTENA, POSTINIT etc, are these required? May be we should review this value as to what all we need to enable.

@marcuschangarm
Copy link
Contributor Author

@bulislaw

I've added comments and wrote a short porting guide: ARMmbed/mbed-os-5-docs#413

@SenRamakri

I've moved the generic ITM register settings out into a separate mbed_itm_api.c file so it can be shared. Each target itm_api.c will only be responsible for setting up it's own clock and SWO pin. I've also replaced the magic numbers with named bit positions.

@marcuschangarm
Copy link
Contributor Author

/morph build

@mbed-ci
Copy link

mbed-ci commented Feb 15, 2018

Build : SUCCESS

Build number : 1143
Build artifacts/logs : http://mbed-os.s3-website-eu-west-1.amazonaws.com/?prefix=builds/5956/

Triggering tests

/morph test
/morph uvisor-test
/morph export-build

@mbed-ci
Copy link

mbed-ci commented Feb 15, 2018

@mbed-ci
Copy link

mbed-ci commented Feb 15, 2018

@marcuschangarm
Copy link
Contributor Author

/morph build

@mbed-ci
Copy link

mbed-ci commented Feb 15, 2018

Build : SUCCESS

Build number : 1153
Build artifacts/logs : http://mbed-os.s3-website-eu-west-1.amazonaws.com/?prefix=builds/5956/

Triggering tests

/morph test
/morph uvisor-test
/morph export-build
/morph mbed2-build

@mbed-ci
Copy link

mbed-ci commented Feb 15, 2018

@mbed-ci
Copy link

mbed-ci commented Feb 16, 2018

Marcus Chang added 3 commits February 16, 2018 08:24
HAL API for initializing the ITM and setting SWO debug output.
Actual debug output implemented as SWO FileHandle.
@marcuschangarm
Copy link
Contributor Author

/morph build

@mbed-ci
Copy link

mbed-ci commented Feb 16, 2018

Build : SUCCESS

Build number : 1163
Build artifacts/logs : http://mbed-os.s3-website-eu-west-1.amazonaws.com/?prefix=builds/5956/

Triggering tests

/morph test
/morph uvisor-test
/morph export-build
/morph mbed2-build

@mbed-ci
Copy link

mbed-ci commented Feb 16, 2018

@mbed-ci
Copy link

mbed-ci commented Feb 16, 2018

@cmonr cmonr merged commit 0ceecb9 into ARMmbed:master Feb 16, 2018
@marcuschangarm marcuschangarm deleted the feature-hal-swo branch February 17, 2018 19:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet